package com.mdb.open.trade.resource;

import cn.hutool.core.lang.UUID;
import com.mdb.bc.api.data.ResultEx;
import com.mdb.bc.api.enums.ApiEnum;
import com.mdb.bc.api.enums.ResultCode;
import com.mdb.bc.cache.MdbCache;
import com.mdb.bc.logger.LogAnnotation;
import com.mdb.bc.utils.ObjectUtil;
import com.mdb.bc.web.support.SuperResources;
import com.mdb.enums.content.AccountStatusEnum;
import com.mdb.enums.content.ContentTypeEnum;
import com.mdb.open.common.enums.TradeOpenRetCodeEnum;
import com.mdb.open.trade.config.MdbContentProperties;
import com.mdb.open.trade.domain.dto.content.CommonUploadDto;
import com.mdb.open.trade.domain.dto.content.GetSignatureDto;
import com.mdb.open.trade.domain.dto.product.UploadDto;
import com.mdb.open.trade.domain.po.content.FileInfo;
import com.mdb.open.trade.domain.vo.content.AccountVo;
import com.mdb.open.trade.domain.vo.content.InnerUploadVo;
import com.mdb.open.trade.domain.vo.product.SignatureVo;
import com.mdb.open.trade.domain.vo.product.UploadVo;
import com.mdb.open.trade.facade.ContentFacade;
import com.mdb.user.LoginUserInfoHelper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;

/**
 * 文件服务
 * 上传下载
 *
 * @author liuyi
 * @date 2019-07-03
 */
@Controller
@RequestMapping("file")
@Api(tags = {"文件服务"})
public class FileResource extends SuperResources {

    @Autowired
    private ContentFacade contentFacade;
    @Autowired
    private LoginUserInfoHelper loginUserInfoHelper;
    @Autowired
    private MdbContentProperties mdbContentProperties;

    @Autowired
    private MdbCache mdbCache;

    @LogAnnotation
    @ApiOperation("获取签名串")
    @RequestMapping(value = "/get_signature", method = {RequestMethod.GET})
    @ResponseBody
    public ResultEx<SignatureVo> getSignature(GetSignatureDto dto) {
        String app = loginUserInfoHelper.getApp();

        //内部  根据app查询对应与秘钥，判断文件上传账号是否正常
        ResultEx<AccountVo> accountVoResultEx = contentFacade.getAccountByAccountId(app);
        AccountVo account = accountVoResultEx.getData();
        if (accountVoResultEx.isFailed() || ObjectUtil.isEmpty(account)) {
            return ResultEx.makeResult(TradeOpenRetCodeEnum.CE_ORIGIN_VALID);
        }
        if (!account.getStatus().equals(AccountStatusEnum.NORMAL.getValue())) {
            return ResultEx.makeResult(TradeOpenRetCodeEnum.ACCOUNT_STATUS_EXCEPTION);
        }

        //生成signature并存入缓存,有效期固定
        String signature = UUID.randomUUID().toString();
        mdbCache.setEx(mdbContentProperties.getCacheKeyBase() + signature, app, mdbContentProperties.getValidTime(), TimeUnit.MILLISECONDS);

        SignatureVo signatureVo = new SignatureVo();
        signatureVo.setSignature(signature);
        signatureVo.setValidTime(mdbContentProperties.getValidTime());

        return ResultEx.ok(signatureVo);
    }

    @LogAnnotation
    @ApiOperation("文件上传")
    @PostMapping("/upload")
    @ResponseBody
    public ResultEx<UploadVo> tokenUpload(@RequestParam("uploadFile") MultipartFile uploadFile, UploadDto uploadDto) {
        String app = loginUserInfoHelper.getApp();
        String userId = loginUserInfoHelper.getUserId(false);
//        String userId = "111";
        //判断signature是否已失效 并获取signature信息
        String cacheStr = mdbCache.get(mdbContentProperties.getCacheKeyBase() + uploadDto.getSignature());
        if (ObjectUtil.isEmpty(cacheStr) || !cacheStr.equals(app)) {
            return ResultEx.makeResult(TradeOpenRetCodeEnum.INVALID_SIGNATURE);
        }

        CommonUploadDto commonUploadDto = new CommonUploadDto();
        commonUploadDto.setApp(app);
        commonUploadDto.setUserId(userId);
        commonUploadDto.setSignature(uploadDto.getSignature());
//        commonUploadDto.setBizKey(uploadDto.getBizKey());
        commonUploadDto.setFileType(uploadDto.getFileType());
        ResultEx<InnerUploadVo> uploadVoResultEx = contentFacade.upload(uploadFile, commonUploadDto);

        return convertObjectResult(uploadVoResultEx, UploadVo.class);
    }

    @LogAnnotation
    @ApiOperation("文件下载")
    @RequestMapping(value = "/download/{fileNo}", method = {RequestMethod.GET})
    public ResultEx download(@ApiParam(name = "文件编号") @PathVariable("fileNo") String fileNo, HttpServletResponse response, HttpServletRequest request) {
        //TODO 增加refer验证

        String realFileNo = getRealFileNo(fileNo);

        FileInfo fileInfo = contentFacade.getByFileNo(realFileNo);
        if (ObjectUtil.isEmpty(fileInfo)) {
            return ResultEx.makeDataNotExistsResult(ResultCode.DATA_NOT_EXISTS.getText());
        }

        response.setCharacterEncoding(request.getCharacterEncoding());
        ContentTypeEnum contentTypeEnum = ApiEnum.parse(ContentTypeEnum.class, fileInfo.getSuffix().toLowerCase());
        if (ObjectUtil.isEmpty(contentTypeEnum)) {
            contentTypeEnum = ContentTypeEnum.DEFAULT;
        }
        response.setContentType(contentTypeEnum.getText());
        FileInputStream fis = null;
        try {
            if (contentTypeEnum.getValue().equals(ContentTypeEnum.DEFAULT.getValue())) {
                response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileInfo.getFileName(), "utf-8"));
            } else {
                response.setHeader("Content-Disposition", "inline; filename=" + URLEncoder.encode(fileInfo.getFileName(), "utf-8"));
            }
            File file = new File(fileInfo.getFileUri());
            fis = new FileInputStream(file);

            IOUtils.copy(fis, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            e.printStackTrace();
            return ResultEx.fail();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return ResultEx.ok();
    }

    /**
     * 获取文件真实编号
     */
    private String getRealFileNo(String fileNo) {
        if (fileNo.contains(".")) {
            return fileNo.substring(0, fileNo.lastIndexOf("."));
        }
        return fileNo;
    }
}
